home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / wrlib / nxpm.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-14  |  13.5 KB  |  654 lines

  1. /* nxpm.c - load "normalized" XPM image
  2.  * 
  3.  *  Raster graphics library
  4.  * 
  5.  *  Copyright (c) 1997 Alfredo K. Kojima
  6.  *
  7.  *  This library is free software; you can redistribute it and/or
  8.  *  modify it under the terms of the GNU Library General Public
  9.  *  License as published by the Free Software Foundation; either
  10.  *  version 2 of the License, or (at your option) any later version.
  11.  *  
  12.  *  This library is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  *  Library General Public License for more details.
  16.  *  
  17.  *  You should have received a copy of the GNU Library General Public
  18.  *  License along with this library; if not, write to the Free
  19.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  */
  21.  
  22. #include <config.h>
  23.  
  24. /* AIX requires this to be the first thing in the file.  */
  25. #ifdef __GNUC__
  26. # define alloca __builtin_alloca
  27. #else
  28. # if HAVE_ALLOCA_H
  29. #  include <alloca.h>
  30. # else
  31. #  ifdef _AIX
  32. #   pragma alloca
  33. #  else
  34. #   ifndef alloca /* predefined by HP cc +Olibcalls */
  35. char *alloca ();
  36. #   endif
  37. #  endif
  38. # endif
  39. #endif
  40.  
  41.  
  42. #include <stdlib.h>
  43. #include <stdio.h>
  44. #include <string.h>
  45. #include <assert.h>
  46. #include <errno.h>
  47.  
  48. #include "wraster.h"
  49.  
  50.  
  51. /*
  52.  * Restricted support for XPM images.
  53.  * 
  54.  * The images must be in the following "normalized" format:
  55.  *
  56.  *
  57.  * line       content
  58.  * 1            signature comment
  59.  * 2        ignored ( normally "static char *xpm[] = {" )
  60.  * 3        "width height color_count chars" where chars is 1 or 2
  61.  * 4            color definitions. Only c values with #rrggbb or #rrrrggggbbb
  62.  *            format OR None
  63.  * n        data
  64.  *
  65.  * - no comments or blank lines are allowed, except for the signature
  66.  * - all lines must have at most 256 characters
  67.  * - no white spaces allowed at left of each line
  68.  */
  69.  
  70. #define LINEWIDTH 64
  71.  
  72. #ifndef USE_XPM
  73.  
  74.  
  75. RImage*
  76. RGetImageFromXPMData(RContext *context, char **data)
  77. {
  78.     RImage *image = NULL;
  79.     unsigned char *color_table[4];
  80.     unsigned short *symbol_table;
  81.     unsigned char *r, *g, *b, *a;
  82.     int i, j, k, line = 0;
  83.     int transp;
  84.     unsigned short color;
  85.     int bsize;
  86.     int w, h, ccount, csize;
  87.  
  88.     if (sscanf(data[line++], "%i %i %i %i", &w, &h, &ccount, &csize)!=4
  89.     || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
  90.     goto bad_format;
  91.     
  92.     if (csize!=1 && csize!=2) 
  93.     goto bad_format;
  94.  
  95.     color_table[0] = alloca(ccount);
  96.     color_table[1] = alloca(ccount);
  97.     color_table[2] = alloca(ccount);
  98.     color_table[3] = alloca(ccount);
  99.     symbol_table = alloca(ccount * sizeof(unsigned short));
  100.     
  101.     bsize = csize * w + 16;
  102.  
  103.     if (!color_table[0] || !color_table[1] || !color_table[2] ||
  104.     !color_table[3] || !symbol_table || !bsize) {
  105.     RErrorCode = RERR_NOMEMORY;
  106.     alloca(0);
  107.     return NULL;
  108.     }
  109.  
  110.     transp = 0;
  111.     /* get color table */
  112.     for (i=0; i<ccount; i++) {
  113.     symbol_table[i] = data[line][0];
  114.     if (csize==2)
  115.         symbol_table[i] |= data[line][1]<<8;
  116.  
  117.     j = csize;
  118.     while (data[line][j]!='#' && data[line][j]!=0
  119.            && data[line][j]!='N') j++;
  120.  
  121.     if (data[line][j]=='#') {
  122.         unsigned int red, green, blue;
  123.         
  124.         k = 0;
  125.         j++;
  126.         while (data[line][j+k]!=0) k++;
  127.         if (k==6) {
  128.         if (sscanf(&(data[line][j]), "%2x%2x%2x", &red, &green, &blue)!=3)
  129.             goto bad_format;
  130.         } else if (k==12) {        
  131.         if (sscanf(&(data[line][j]), "%4x%4x%4x", &red, &green, &blue)!=3)
  132.             goto bad_format;
  133.         red >>= 8;
  134.         green >>= 8;
  135.         blue >>= 8;
  136.         } else
  137.         goto bad_format;
  138.         
  139.         color_table[0][i] = red;
  140.         color_table[1][i] = green;
  141.         color_table[2][i] = blue;
  142.         color_table[3][i] = 255;
  143.     } else if (strncmp(&(data[line][j]), "None", 4)==0
  144.            || strncmp(&(data[line][j]), "none", 4)==0) {
  145.         color_table[3][i] = 0;
  146.         transp = 1;
  147.     } else {
  148.         goto bad_format;
  149.     }
  150.     line++;
  151.     }
  152.  
  153.     image = RCreateImage(w, h, transp);
  154.     if (!image) {
  155.     alloca(0);
  156.     return NULL;
  157.     }
  158.  
  159.     r = image->data;
  160.     g = image->data+1;
  161.     b = image->data+2;
  162.     if (image->format == RRGBAFormat)
  163.     a = image->data+3;
  164.     else
  165.     a = NULL;
  166.  
  167.     for (i=0; i<h; i++) {
  168.     if (csize==1) {
  169.         for (j=0; j<w; j++) {
  170.         color = data[line][j];
  171.         
  172.         for (k=0; k<ccount; k++) {
  173.             if (symbol_table[k] == color)
  174.             break;
  175.         }
  176.         if (k==ccount)
  177.             k = 0;
  178.         
  179.         *(r++) = color_table[0][k];
  180.         *(g++) = color_table[1][k];
  181.         *(b++) = color_table[2][k];
  182.         if (a)
  183.             *(a++) = color_table[3][k];
  184.         }
  185.     } else {
  186.         for (j=0; j<w*2; j++) {
  187.         color = data[line][j++];
  188.         color |= data[line][j];
  189.         
  190.         for (k=0; k<ccount; k++) {
  191.             if (symbol_table[k] == color)
  192.             break;
  193.         }    
  194.         if (k==ccount)
  195.             k = 0;
  196.     
  197.         *(r++) = color_table[0][k];
  198.         *(g++) = color_table[1][k];
  199.         *(b++) = color_table[2][k];
  200.         if (a)
  201.             *(a++) = color_table[3][k];
  202.         }
  203.     }
  204.     line++;
  205.     }
  206.  
  207. #ifdef C_ALLOCA
  208.     alloca(0);
  209. #endif
  210.     return image;
  211.  
  212.   bad_format:
  213.     RErrorCode = RERR_BADIMAGEFILE;
  214. #ifdef C_ALLOCA
  215.     alloca(0);
  216. #endif
  217.     if (image)
  218.     RDestroyImage(image);
  219.     return NULL;
  220. }
  221.  
  222.  
  223.  
  224. RImage*
  225. RLoadXPM(RContext *context, char *file, int index)
  226. {
  227.     RImage *image = NULL;
  228.     char line[LINEWIDTH+1];
  229.     char *buffer;
  230.     unsigned char *color_table[4];
  231.     unsigned short *symbol_table;
  232.     unsigned char *r, *g, *b, *a;
  233.     int i, j, k;
  234.     int transp;
  235.     unsigned short color;
  236.     int bsize;
  237.     int w, h, ccount, csize;
  238.     FILE *f;
  239.     
  240.     f = fopen(file, "r");
  241.     if (!f) {
  242.     RErrorCode = RERR_OPEN;
  243.     return NULL;
  244.     }
  245.     /* sig */
  246.     if (!fgets(line, LINEWIDTH, f))
  247.     goto bad_file;
  248.     /* declaration */
  249.     if (!fgets(line, LINEWIDTH, f))
  250.     goto bad_file;
  251.  
  252.     /* data */
  253.     if (!fgets(line, LINEWIDTH, f))
  254.     goto bad_file;
  255.     
  256.     if (line[0]=='/')
  257.     if (!fgets(line, LINEWIDTH, f))
  258.         goto bad_file;
  259.  
  260.     if (sscanf(line, "\"%i %i %i %i\"", &w, &h, &ccount, &csize)!=4
  261.     || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
  262.     goto bad_file;
  263.     
  264.     if (csize!=1 && csize!=2) 
  265.     goto bad_format;
  266.  
  267.     color_table[0] = alloca(ccount);
  268.     color_table[1] = alloca(ccount);
  269.     color_table[2] = alloca(ccount);
  270.     color_table[3] = alloca(ccount);
  271.     symbol_table = alloca(ccount * sizeof(unsigned short));
  272.     
  273.     bsize = csize * w + 16;
  274.     buffer = alloca(bsize);
  275.  
  276.     if (!color_table[0] || !color_table[1] || !color_table[2] ||
  277.     !color_table[3] || !symbol_table || !bsize) {
  278.     RErrorCode = RERR_NOMEMORY;
  279.     fclose(f);
  280.     alloca(0);
  281.     return NULL;
  282.     }
  283.  
  284.     transp = 0;
  285.     /* get color table */
  286.     for (i=0; i<ccount; i++) {
  287.     if (!fgets(line, LINEWIDTH, f)) 
  288.         goto bad_file;
  289.     if (line[0]=='/')
  290.         if (!fgets(line, LINEWIDTH, f))
  291.         goto bad_file;
  292.  
  293.     symbol_table[i] = line[1];
  294.     if (csize==2)
  295.         symbol_table[i] |= line[2]<<8;
  296.  
  297.     j = csize+1;
  298.     while (line[j]!='#' && line[j]!='"' && line[j]!=0 && line[j]!='N') j++;
  299.  
  300.     if (line[j]=='#') {
  301.         unsigned int red, green, blue;
  302.         
  303.         k = 0;
  304.         j++;
  305.         while (line[j+k]!='"' && line[j+k]!=0) k++;
  306.         if (k==6) {
  307.         if (sscanf(&(line[j]), "%2x%2x%2x", &red, &green, &blue)!=3)
  308.             goto bad_format;
  309.         } else if (k==12) {        
  310.         if (sscanf(&(line[j]), "%4x%4x%4x", &red, &green, &blue)!=3)
  311.             goto bad_format;
  312.         red >>= 8;
  313.         green >>= 8;
  314.         blue >>= 8;
  315.         } else
  316.         goto bad_format;
  317.         
  318.         color_table[0][i] = red;
  319.         color_table[1][i] = green;
  320.         color_table[2][i] = blue;
  321.         color_table[3][i] = 255;
  322.     } else if (strncmp(&(line[j]), "None", 4)==0
  323.            || strncmp(&(line[j]), "none", 4)==0) {
  324.         color_table[3][i] = 0;
  325.         transp = 1;
  326.     } else {
  327.         goto bad_format;
  328.     }
  329.     }
  330.  
  331.     image = RCreateImage(w, h, transp);
  332.     if (!image) {
  333.     fclose(f);
  334.     alloca(0);
  335.     return NULL;
  336.     }
  337.  
  338.     r = image->data;
  339.     g = image->data+1;
  340.     b = image->data+2;
  341.     if (image->format == RRGBAFormat)
  342.     a = image->data+3;
  343.     else
  344.     a = NULL;
  345.  
  346.     for (i=0; i<h; i++) {
  347.     if (!fgets(buffer, bsize, f))
  348.         goto bad_file;
  349.     if (buffer[0]=='/')
  350.         if (!fgets(buffer, bsize, f))
  351.         goto bad_file;
  352.     
  353.     if (csize==1) {
  354.         for (j=1; j<=w; j++) {
  355.         color = buffer[j];
  356.         
  357.         for (k=0; k<ccount; k++) {
  358.             if (symbol_table[k] == color)
  359.             break;
  360.         }
  361.         if (k==ccount)
  362.             k = 0;
  363.         
  364.         *(r++) = color_table[0][k];
  365.         *(g++) = color_table[1][k];
  366.         *(b++) = color_table[2][k];
  367.         if (a)
  368.             *(a++) = color_table[3][k];
  369.         }
  370.     } else {
  371.         for (j=1; j<=w*2; j++) {
  372.         color = buffer[j++];
  373.         color |= buffer[j] << 8;
  374.         
  375.         for (k=0; k<ccount; k++) {
  376.             if (symbol_table[k] == color)
  377.             break;
  378.         }
  379.         if (k==ccount) {
  380.             k = 0;
  381.         }
  382.     
  383.         *(r++) = color_table[0][k];
  384.         *(g++) = color_table[1][k];
  385.         *(b++) = color_table[2][k];
  386.         if (a)
  387.             *(a++) = color_table[3][k];
  388.         }
  389.     }
  390.     }
  391.  
  392.     fclose(f);
  393. #ifdef C_ALLOCA
  394.     alloca(0);
  395. #endif
  396.     return image;
  397.  
  398.   bad_format:
  399.     RErrorCode = RERR_BADIMAGEFILE;
  400.     fclose(f);
  401. #ifdef C_ALLOCA
  402.     alloca(0);
  403. #endif
  404.     if (image)
  405.     RDestroyImage(image);
  406.     return NULL;
  407.     
  408.   bad_file:
  409.     RErrorCode = RERR_BADIMAGEFILE;
  410.     fclose(f);
  411. #ifdef C_ALLOCA
  412.     alloca(0);
  413. #endif
  414.     if (image)
  415.     RDestroyImage(image);
  416.     return NULL;
  417. }
  418.  
  419. #endif
  420.  
  421.  
  422. typedef struct XPMColor {
  423.     unsigned char red;
  424.     unsigned char green;
  425.     unsigned char blue;
  426.     int index;
  427.     struct XPMColor *next;
  428. } XPMColor;
  429.  
  430.  
  431.  
  432. #define I2CHAR(i)    ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
  433. #define CINDEX(xpmc)    (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
  434.  
  435.  
  436.  
  437. static XPMColor*
  438. lookfor(XPMColor *list, int index)
  439. {
  440.     if (!list)
  441.     return NULL;
  442.  
  443.     for (; list!=NULL; list=list->next) {
  444.     if (CINDEX(list) == index)
  445.         return list;
  446.     }
  447.     return NULL;
  448. }
  449.  
  450. /*
  451.  * Looks for the color in the colormap and inserts if it is not found.
  452.  * 
  453.  * list is a binary search list. The unbalancing problem is just ignored.
  454.  * 
  455.  * Returns False on error
  456.  */
  457. static Bool
  458. addcolor(XPMColor **list, unsigned r, unsigned g, unsigned b, int *colors)
  459. {
  460.     XPMColor *tmpc;
  461.     XPMColor *newc;
  462.     int index;
  463.  
  464.     index = r<<16|g<<8|b;
  465.     tmpc = *list;
  466.  
  467.     tmpc = lookfor(*list, index);
  468.  
  469.     if (tmpc)
  470.     return True;
  471.  
  472.     newc = malloc(sizeof(XPMColor));
  473.  
  474.     if (!newc) {
  475.  
  476.     RErrorCode = RERR_NOMEMORY;
  477.  
  478.     return False;
  479.     }
  480.  
  481.     newc->red = r;
  482.     newc->green = g;
  483.     newc->blue = b;
  484.     newc->next = *list;
  485.     *list = newc;
  486.  
  487.     (*colors)++;
  488.  
  489.     return True;
  490. }
  491.  
  492.  
  493. static char*
  494. index2str(char *buffer, int index, int charsPerPixel)
  495. {
  496.     int i;
  497.  
  498.     for (i=0; i<charsPerPixel; i++) {
  499.     buffer[i] = I2CHAR(index&63);
  500.     index >>= 6;
  501.     }
  502.     buffer[i] = 0;
  503.     
  504.     return buffer;
  505. }
  506.  
  507.  
  508. static void
  509. outputcolormap(FILE *file, XPMColor *colormap, int charsPerPixel)
  510. {
  511.     int index;
  512.     char buf[128];
  513.  
  514.     if (!colormap)
  515.     return;
  516.  
  517.     for (index=0; colormap!=NULL; colormap=colormap->next,index++) {
  518.     colormap->index = index;
  519.     fprintf(file, "\"%s c #%02x%02x%02x\",\n", 
  520.         index2str(buf, index, charsPerPixel), colormap->red,
  521.         colormap->green, colormap->blue);
  522.     }
  523. }
  524.  
  525.  
  526. static void
  527. freecolormap(XPMColor *colormap)
  528. {
  529.     XPMColor *tmp;
  530.     
  531.     while (colormap) {
  532.     tmp = colormap->next;
  533.     free(colormap);
  534.     colormap = tmp;
  535.     }
  536. }
  537.  
  538.  
  539.  
  540. /* save routine is common to internal support and library support */
  541. Bool 
  542. RSaveXPM(RImage *image, char *filename)
  543. {
  544.     FILE *file;
  545.     int x, y;
  546.     int colorCount=0;
  547.     int charsPerPixel;
  548.     XPMColor *colormap = NULL;
  549.     XPMColor *tmpc;
  550.     int i;
  551.     int ok = 0;
  552.     unsigned char *r, *g, *b, *a;
  553.     char transp[16];
  554.     char buf[128];
  555.  
  556.     file = fopen(filename, "w+");
  557.     if (!file) {
  558.     RErrorCode = RERR_OPEN;
  559.     return False;
  560.     }
  561.  
  562.     fprintf(file, "/* XPM */\n");
  563.  
  564.     fprintf(file, "static char *image[] = {\n");
  565.  
  566.     r = image->data;
  567.     g = image->data+1;
  568.     b = image->data+2;
  569.     if (image->format == RRGBAFormat)
  570.     a = image->data+3;
  571.     else
  572.     a = NULL;
  573.  
  574.     /* first pass: make colormap for the image */
  575.     if (a)
  576.     colorCount = 1;
  577.     for (y = 0; y < image->height; y++) {
  578.     for (x = 0; x < image->width; x++) {
  579.         if (!a || *a++>127)
  580.         if (!addcolor(&colormap, *r, *g, *b, &colorCount)) {
  581.             goto uhoh;
  582.         }
  583.         r++; g++; b++;
  584.     }
  585.     }
  586.  
  587.     charsPerPixel = 1;
  588.     while ((1 << charsPerPixel*6) < colorCount)
  589.         charsPerPixel++;
  590.  
  591.     /* write header info */
  592.     fprintf(file, "\"%i %i %i %i\",\n", image->width, image->height, 
  593.         colorCount, charsPerPixel);
  594.  
  595.     /* write colormap data */
  596.     if (image->data[3]) {
  597.     for (i=0; i<charsPerPixel; i++)
  598.         transp[i] = ' ';
  599.     transp[i] = 0;
  600.  
  601.     fprintf(file, "\"%s c None\",\n", transp);
  602.     }
  603.     
  604.     i = 0;
  605.     outputcolormap(file, colormap, charsPerPixel);
  606.  
  607.  
  608.     r = image->data;
  609.     g = image->data+1;
  610.     b = image->data+2;
  611.     if (image->format == RRGBAFormat)
  612.     a = image->data+3;
  613.     else
  614.     a = NULL;
  615.  
  616.     /* write data */
  617.     for (y = 0; y < image->height; y++) {
  618.  
  619.     fprintf(file, "\"");
  620.  
  621.     for (x = 0; x < image->width; x++) {
  622.  
  623.         if (!a || *a++>127) {
  624.         tmpc = lookfor(colormap, (unsigned)*r<<16|(unsigned)*g<<8|(unsigned)*b);
  625.  
  626.         fprintf(file, index2str(buf, tmpc->index, charsPerPixel));
  627.         } else {
  628.         fprintf(file, transp);
  629.         }
  630.  
  631.         r++; g++; b++;
  632.     }
  633.  
  634.     if (y < image->height-1)
  635.         fprintf(file, "\",\n");
  636.     else
  637.         fprintf(file, "\"};\n");
  638.     }
  639.  
  640.     ok = 1;
  641. uhoh:
  642.     errno = 0;
  643.     fclose(file);
  644.     if (ok && errno==ENOSPC) {
  645.     RErrorCode = RERR_WRITE;
  646.     }
  647.  
  648.     freecolormap(colormap);
  649.  
  650.     return ok ? True : False;
  651. }
  652.  
  653.  
  654.